// CSmalltalk.h --------------------------------------------------------------------------------//
#include <stdio.h>                                                                              //
#include <stdlib.h>                                                                             //
#include <ctype.h>                                                                              //
#include <string.h>                                                                             //
#include <setjmp.h>                                                                             //
#include <signal.h>                                                                             //
#include <assert.h>                                                                             //
//////////////////////////////////////////////////////////////////////////////////////////////////

// {
    //{
#ifndef __cplusplus
# define true  1
# define false 0
#endif
#define ENABLE (true)
#define DISABLE (false)

#if ENABLE&&!DISABLE // CSmalltalk-parse Macro
# define registeExcept(mt)   \
(                     \
  signal(SIGABRT,mt), \
  signal(SIGFPE,mt),  \
  signal(SIGILL,mt),  \
  signal(SIGINT,mt),  \
  signal(SIGSEGV,mt), \
  signal(SIGTERM,mt), \
  true                \
)
# define nil (NULL)
# ifdef NDEBUG
#  define C57LOG(...) return 0
# else
#  define C57LOG(...) fprintf(stdout,__VA_ARGS__)
# endif
#endif

#if ENABLE&&!DISABLE // Try-pack Macro
# define TRINT(EXP) jmp_buf EXP; typedef enum
# define TRY(EXP,JBRN) int JBRN=setjmp(EXP);if(!JBRN)
# define EXPINT(JBRN) int JBRN;
# define EXPTRY(EXP,JBRN) JBRN=setjmp(EXP);if(!JBRN)
# define CATCH(JBRN,VAL) else if(JBRN==VAL)
# define THROW(EXP,VAL) (longjmp(EXP,VAL))
# define FINALLY() if(true)
#endif

#undef true
#undef false

#if !defined(__cplusplus)
  typedef enum {false, true} bool; // bool Type
#else
# define bool  bool
# define false false
# define true  true
#endif
TRINT(C57Exp) {
	NORMAL, PROGRAM_ABORT,
	UNKNOWN, NOENOUGH_MEM
} EXCEPT_VAL;
EXPINT (Exp);
 
#define $ (*model)
#define detect ((short)-1)
typedef char* string;
//}
typedef struct {
	char* rcode;
	short limit;
	string*sybl;
	bool  next;
	short* bracks;
	int btop;
	char* executes;
	int etop;
} CSmalltalk;
typedef struct {
	string   path;
	short    mlt;
	string   rdata;
	string   symbol;
} C57Object;
void exprintf(const char*fmt,...);
bool split(CSmalltalk*);
bool parse(CSmalltalk*);
bool flint(void);
bool NeutralInt(CSmalltalk*);
string malloc_string(const string);

C57Object objPool[128];
short temp,ptop=0,lmt,ftop;
char*substr(char*str,short beg,short end) {
	char*sub=(char*)malloc((end-beg+1)*sizeof(char));
	if(NULL==sub) THROW(C57Exp, NOENOUGH_MEM);
	for(short i = 0; i<(end-beg+1); i++) {
		sub[i]=str[i+beg];
	}
	if(sub[strlen(sub)-1]>=32&&sub[strlen(sub)-1]<=126); 
	else sub[strlen(sub)-1]=0;
	return sub;
}
string remove_bracks(const string str) {
	string sret=(string)malloc(sizeof(char)*strlen(str));
	if(NULL==sret) THROW(C57Exp, NOENOUGH_MEM);
	bool instr=false;
	for(short i = 0, j = 0; i < strlen(str); i++) {
		if(sret[i]=='\'') {
			sret[j++]='\'';
		} else if((sret[i]=='('||sret[i]==')')&&!instr) {
			continue;
		} else {
			sret[j++]=str[i];
		}
	}
	return sret;
}
int count5char(const string str, int ch) {
	int cnt=0, l=0;
	bool instr=false;
	for(l=0; l<strlen(str); l++) {
		if(str[l]=='\'') {
			if(!instr) instr=true;
			else if(str[l-1]!='\\') instr=false;
			else;
			continue;
		}
		if(!instr) cnt+=(str[l]==ch);
	}
	return cnt;
}
bool is_separate(const string str) {
	char alp=-1;
	for(short i = 0; i < strlen(str); i++) {
		if(isalpha(str[i])) {
		} else ;
		  if(str[i]=='-');
		  else if(str[i]=='(');
		  else if(str[i]==')');
		  else if(str[i]==' ');
		  else if(str[i]==';');
		  else if(isalpha(str[i])) {
		  } else return false;
	}
	return true;
}
bool parse(CSmalltalk* model) {
	bool instr=false;
	CSmalltalk vodel={.limit=detect};
	short i,j,k,h,w,s,cnt0,cnt1;
	
	if(model->limit==detect) model->limit=strlen(model->rcode);
	
	$.bracks=(short*)malloc(model->limit*sizeof(short));
	if(NULL==$.bracks) THROW(C57Exp, NOENOUGH_MEM);
	$.btop=0;
	for(i=0; i<(model->limit); i++) {
		if(model->rcode[i]=='\''&&model->rcode[i-1]!='\\') instr^=1;
		
		if(model->rcode[i]=='('&&!instr)
		 $.bracks[$.btop++]= +i;
		if(model->rcode[i]==')'&&!instr)
		 $.bracks[$.btop++]= -i;
	}
	$.executes=(char*)malloc(4096*sizeof(char));
	if(NULL==$.executes) THROW(C57Exp, NOENOUGH_MEM);
	static char alp='a';
	for(i=0, cnt0=0; i<($.btop); i++) {
		if($.bracks[i]<0) {
			cnt0++; // skip
			for(j=i, cnt1=0; j>=0; j--) {
				if($.bracks[j]>=0) cnt1++;
				if(cnt1==cnt0) break;
			}
			vodel.rcode=substr(model->rcode,$.bracks[j],-$.bracks[i]);
			if(!is_separate(vodel.rcode)) {
				k=i;
				if(count5char(vodel.rcode,'(')!=count5char(vodel.rcode,')')) {
					parse(&vodel);
					while(count5char(vodel.rcode,'(')!=count5char(vodel.rcode,')')) {
						if(k==strlen(vodel.rcode)-1) break;
						if($.bracks[k]>=0);
						vodel.rcode=substr(model->rcode,$.bracks[j],-$.bracks[k]);
						k++;	
					}
					--k;
				}
				printf("  #%c as ({%s} execute);\n",alp,remove_bracks(vodel.rcode));
				alp++;
				model->rcode[$.bracks[j]+1]=alp-1,
				model->rcode[$.bracks[j]]='(',
				model->rcode[-$.bracks[k]]=')';
				for(short w=$.bracks[j]+2; w<-$.bracks[k]; w++) model->rcode[w]='-';
			}
		}
	}
	free($.executes);
	return true;
	_using: w=w, s=s, k=k, h=h;
	goto _using;
}
bool flint(void) {
	ptop=0;
	return true;
}
bool NeutralInt(CSmalltalk* model) { // Still writing...
  	_using: model=model;
	// goto _using;
  	
	return true;
}
string malloc_string(const string str) {
	string sret=(string)malloc(sizeof(char)*strlen(str));
	if(NULL==sret) THROW(C57Exp, NOENOUGH_MEM);
	strcpy(sret,str);
	return sret;
}
void caught(int code) {
    if(code^SIGINT&&code^SIGTERM) {
        C57LOG("[@CSmalltalk logout] Caught a FATAL-ERROR %s\r\n",strerror(code));
        exit(code);
    } else THROW(C57Exp,PROGRAM_ABORT);
    return ;
}
#undef $
//}
